package ubadb.bench;

import ubadb.bench.tests.Test;
import ubadb.core.common.TableId;
import ubadb.core.components.bufferManager.bufferPool.BufferPool;
import ubadb.core.components.bufferManager.bufferPool.PerTableBufferPool;
import ubadb.core.components.bufferManager.bufferPool.pools.single.SingleBufferPool;
import ubadb.core.components.bufferManager.bufferPool.replacementStrategies.PageReplacementStrategy;
import ubadb.core.components.bufferManager.bufferPool.replacementStrategies.beststrategy.BestReplacementStrategy;
import ubadb.core.components.bufferManager.bufferPool.replacementStrategies.lru.LRUReplacementStrategy;
import ubadb.core.components.bufferManager.bufferPool.replacementStrategies.mru.MRUReplacementStrategy;
import ubadb.core.components.bufferManager.bufferPool.replacementStrategies.random.RandomReplacementStrategy;
import ubadb.core.exceptions.BufferPoolException;

public abstract class MultipleBufferPoolTestCase implements BufferPoolTestCase {

	private final String name;

	private MultipleBufferPoolTestCase(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	@Override
	public void executedRequest() {

	}

	public abstract BufferPool createBufferPool(int poolSize, Test test);

	public static final MultipleBufferPoolTestCase[] CASES = new MultipleBufferPoolTestCase[] {
			new MultipleBufferPoolTestCase("Best") {

				private BestReplacementStrategy strategy;

				@Override
				public BufferPool createBufferPool(int poolSize, Test test) {
					strategy = new BestReplacementStrategy(test.getTrace());
					return new SingleBufferPool(poolSize, strategy);
				}

				@Override
				public void executedRequest() {
					strategy.moveNextPositionInTrace();
				}

			}, new MultipleBufferPoolTestCase("Random") {

				@Override
				public BufferPool createBufferPool(int poolSize, Test test) {
					return new SingleBufferPool(poolSize,
							new RandomReplacementStrategy());
				}
			}, new MultipleBufferPoolTestCase("S-MRU") {

				@Override
				public BufferPool createBufferPool(int poolSize, Test test) {
					return new SingleBufferPool(poolSize,
							new MRUReplacementStrategy());
				}
			}, new MultipleBufferPoolTestCase("S-LRU") {

				@Override
				public BufferPool createBufferPool(int poolSize, Test test) {
					return new SingleBufferPool(poolSize,
							new LRUReplacementStrategy());
				}
			}, new MultipleBufferPoolTestCase("M-MRU") {

				@Override
				public BufferPool createBufferPool(int poolSize, Test test) {
					return createMultipleBuffer(test, poolSize,
							new MRUReplacementStrategy());
				}
			}, new MultipleBufferPoolTestCase("M-LRU") {

				@Override
				public BufferPool createBufferPool(int poolSize, Test test) {
					return createMultipleBuffer(test, poolSize,
							new LRUReplacementStrategy());
				}
			}

	};

	private static final PerTableBufferPool createMultipleBuffer(Test test,
			int poolSize, PageReplacementStrategy st) {
		int totalSize = test.getTableSize(null);
		PerTableBufferPool pool = new PerTableBufferPool();
		for (TableId table : test.getTables()) {
			int tableSize = test.getTableSize(table);
			int tablePoolSize = (poolSize * tableSize) / totalSize;
			if (tablePoolSize < test.getMinBuffersFor(table))
				return null;
			try {
				pool.addNewBufferPoolForTable(table, new SingleBufferPool(
						tablePoolSize, st));
			} catch (BufferPoolException e) {
				throw new RuntimeException("Error adding pool", e);
			}
		}
		return pool;
	}
}